package cs6238.common.message.response;

import static org.junit.Assert.*;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.junit.Test;

import cs6238.common.FileInfo;
import cs6238.common.message.MessageFactory;
import cs6238.common.message.response.LsResponse;
import cs6238.common.message.response.StandardResponse;

public class ResponseSerialization {

	private FileInfo createFileInfo(){
		FileInfo info = new FileInfo();
		info.setFileId(UUID.randomUUID());
		info.setFilename("Human readable.txt");
		info.setOwningHost("host");
		return info;
	}
	
	
	private void verifyLsResponse_SerializeDeserialize(List<FileInfo> fileInfos){
		LsResponse response = new LsResponse();
		response.setFileInfoList(fileInfos);
		byte[] bytes = response.serialize();
		
		LsResponse fromBytes = (LsResponse)MessageFactory.createResponse(bytes);
		
		assertEquals(response.getFileInfoList().size(), fromBytes.getFileInfoList().size());
		
		List<FileInfo> expectedList = response.getFileInfoList();
		List<FileInfo> actualList = fromBytes.getFileInfoList();
		
		for(int i=0; i<expectedList.size(); i++){
			FileInfo expected = expectedList.get(i);
			FileInfo actual = actualList.get(i);
			
			assertEquals(expected.getFilename(), actual.getFilename());
			assertEquals(expected.getFileId(), actual.getFileId());	
		}
	}
	
	@Test 
	public void testFileInfo_SerializeAndDeserialize(){
		FileInfo info = createFileInfo();
		byte[] infoInBytes = info.serialize();
		
		FileInfo actual = new FileInfo();
		ByteBuffer bb = ByteBuffer.wrap(infoInBytes);
		actual.deserialize(bb);
		
		assertEquals(info.getFilename(), actual.getFilename());
		assertEquals(info.getFileId(), actual.getFileId());
	}
	
	@Test
	public void testLsResponse_EmptyList_SerializeAndDeserialize() {
		verifyLsResponse_SerializeDeserialize(new ArrayList<FileInfo>());
	}
	
	@Test
	public void testLsResponse_WithSeveralValues_SerializeAndDeserialize() {
		List<FileInfo> fileInfos = new ArrayList<FileInfo>();
		fileInfos.add(createFileInfo());
		fileInfos.add(createFileInfo());
		fileInfos.add(createFileInfo());
	
		verifyLsResponse_SerializeDeserialize(fileInfos);
	}
	
	
	@Test
	public void testStandardResponse_NotOk_SerializeAndDeserialize() {
		StandardResponse response = new StandardResponse(false);
		byte[] bytes = response.serialize();
		
		StandardResponse fromBytes = (StandardResponse)MessageFactory.createResponse(bytes);
		assertEquals(response.isOk(), fromBytes.isOk());
	}
	
	@Test
	public void testStandardResponse_Ok_SerializeAndDeserialize() {
		StandardResponse response = new StandardResponse(true);
		byte[] bytes = response.serialize();
		
		StandardResponse fromBytes = (StandardResponse)MessageFactory.createResponse(bytes);
		assertEquals(response.isOk(), fromBytes.isOk());
	}
	
	
	@Test
	public void testListHostsResponse_Empty_SerializeAndDeserialize(){
		ListHostsResponse response = new ListHostsResponse();
		ListHostsResponse fromSerial = (ListHostsResponse)MessageFactory.createResponse(response.serialize());
		
		assertNotNull(fromSerial);
		assertEquals(0, fromSerial.getHosts().size());
	}
	
	@Test
	public void testListHostsResponse_NotEmpty_SerializeAndDeserialize(){
		ListHostsResponse response = new ListHostsResponse();
		List<String> hosts = new ArrayList<String>();
		hosts.add("host1");
		hosts.add("host2");
		hosts.add("host3");
		response.setHosts(hosts);
		
		ListHostsResponse fromSerial = (ListHostsResponse)MessageFactory.createResponse(response.serialize());
		
		assertNotNull(fromSerial);
		assertEquals(3, fromSerial.getHosts().size());
		assertEqual(response.getHosts(), fromSerial.getHosts());
	}
	
	private void assertEqual(List<String> expected, List<String> actual){
		if(expected == null){
			assertNull(actual);
			return;
		}
		
		assertEquals(expected.size(), actual.size());
		for(String string : expected){
			assertTrue(actual.contains(string));
		}
	}
	
	

}
